home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / GNUUCP_2 / SOURCE / GIO.C < prev    next >
Text File  |  1990-07-16  |  25KB  |  918 lines

  1. /*
  2.  * @(#)gio.c 1.8 87/09/29    Copyright 1987 Free Software Foundation, Inc.
  3.  *
  4.  * Copying and use of this program are controlled by the terms of the
  5.  * GNU Emacs General Public License.
  6.  *
  7.  * Derived from:
  8.  * i[$]uuslave.c    1.7 08/12/85 14:04:20
  9.  * which came from the ACGNJ BBS system at +1 201 753 9758.  Original
  10.  * author unknown.
  11.  */
  12.  
  13. #ifndef lint
  14. char gio_version[] = "@(#)gio.c Fort Pond Research-2.6 7/15/90";
  15. #endif
  16.  
  17. #include "includes.h"        /* All the system header files */
  18. #include "uucp.h"
  19.  
  20. extern int errno;
  21.  
  22. /*
  23.  
  24. This program implements the uucp (Unix-to-Unix CoPy) protocol as a
  25. slave (the recipient of a phone call from another Unix system) or, now,
  26. a master (the originator of a phone call).  This
  27. protocol is used to transfer mail, files, and Usenet news from Unix
  28. machine to Unix machine.  UUCP comes with Unix (unless you get a
  29. sleazeoid version like Xenix, where they charge you extra for it).  You
  30. can buy a commercial program for MSDOS, called UULINK, which also
  31. implements this protocol.  UULINK costs $300 and you don't get sources,
  32. though.
  33.  
  34. The protocol requires a full 8-bit data path with no characters inserted
  35. or deleted (e.g. ^S and ^Q are used as DATA characters).  Simple serial
  36. ports and modems do this; most complicated networks do not, at least without
  37. setting up odd modes and such.  Telenet's PC Pursuit works fine though.
  38.  
  39. The basic flow of the protocol is that the calling machine will send down
  40. a line of text saying what it wants to do (send a file, receive a file,
  41. or hang up).  (The lines of text are encapsulated into packets; see below.)
  42. The called machine responds with a "yes" or "no" answer, and if the answer
  43. was yes, it sends or receives the file.  Files are terminated with a
  44. packet containing 0 bytes of data.  Then the system that received the file
  45. sends a "copy succeeded" or "copy failed" line to the other end, and 
  46. they go back to "what do we do now".  A request to hang up should be
  47. answered "no" if the called machine has some mail or files it wants to
  48. send to the calling machine; the two machines reverse roles and the calling
  49. machine goes into "what do we do now".  If a hangup request is answered "yes",
  50. the call is terminated.
  51.  
  52. The data flow described above is actually sent in packets containing
  53. checksums and acknowledgements.  Each packet can either hold a short
  54. control message, e.g. an ack, or a data block.  The data blocks are
  55. numbered with a 3-bit counter, and sent with a checksum.  If the sender
  56. has not received an acknowledgement for a data block within a certain
  57. time, it retransmits the block.  The size of a data block is negotiated
  58. at the start of a call.  To send a block with fewer bytes, a "short
  59. data" block is sent, which is just as big as a "long data" block, but
  60. contains a 1- or 2-byte count of "how many bytes in this block are just
  61. padding".  This is a cute trick since it always works (e.g. if you want
  62. to send 1023 out of 1024 bytes, you only need one byte for the count;
  63. while if you want to send 1 byte out of 1024 then you have enough space
  64. for the count to be 2 bytes).
  65.  
  66. The short control messages are used to start the call and negotiate the
  67. packet size and the "window size", to acknowledge or reject packets,
  68. and to terminate the packet protocol at the end of a call.  The window
  69. size is how many packets one side can send before it will stop and wait
  70. for an acknowledgement from the other side.  A window size of 1 makes
  71. for a half-duplex protocol (which is what uuslave currently
  72. implements), but also makes it easy to implement on micros that don't
  73. handle serial lines with interrupts.  In window 1, you just keep
  74. sending the same packet until the other side acknowledges it.  Unix
  75. always uses a window size of 3, which is the max that can be dealt with
  76. given the 3-bit packet numbers (for reasons that would take more space
  77. than I want to spend here).  This gives much better throughput, but
  78. requires full duplex serial port handling and more complicated
  79. acknowledgement strategies.
  80.  
  81. At the low level, full 8-bit bytes are sent out and received on an async serial
  82. port.  The received data is scanned for a DLE (hex 10) which indicates the
  83. start of a packet, and the next 5 bytes are read and checked.  If they
  84. pass, this is a good packet and it is acted upon.  (If it's a data
  85. packet, we have to read in and check the data part too.)  If the checks
  86. fail, all the bytes read so far should be scanned for another DLE.
  87. */
  88.  
  89. /*
  90.  * UUCP "g" procotol definitions
  91.  */
  92. #define    MAGIC    0125252        /* checksum is subtracted from this */
  93.  
  94. /*
  95.  * What is sent from one machine to the other is a control byte and
  96.  * sometimes a data block following.
  97.  * A packet is a just this, with a frame around the control byte and the
  98.  * data, if any, after the frame.  The frame is 6 bytes long, and looks like:
  99.  *    DLE K C0 C1 C X
  100.  * where:
  101.  *    DLE is a literal ASCII DLE (Data Link Escape) character
  102.  *    K is binary, 9 for a control packet, or the packet size log 2, minus 4
  103.  *        e.g. K = 2 means 64 byte packet since  (K+4) is  6 or 64.
  104.  *                              2         2
  105.  *    C0 and C1 are low, high order checksums for the entire data section, or
  106.  *        are low, high order of (MAGIC minus the control byte).
  107.  *    C is the control byte for the message.
  108.  *    X is the xor of K, C0, C1, and C.
  109.  * If a packet does not satisfy all of the above checks, it is invalid.
  110.  */
  111. #define    DLE    0x10        /* Start of packet indicator */
  112.  
  113. #define    LENBYTE    1        /* Byte offset from DLE to length */
  114. #define    CBYTE    4        /* Byte offset from DLE to control */
  115. #define    FRAMEBYTE 5        /* Byte offset from DLE to end of frame */
  116.  
  117. #define    KCONTROL 9        /* K value for control packets */
  118.  
  119. /*
  120.  * A control byte is split into three bit fields: type, x, and y.
  121.  *     TT XXX YYY
  122.  * Here are the types:
  123.  */
  124. #define    CONTROL    0        /* Control message */
  125. #define    ALTCHN    1        /* Alternate channel message, unused in UUCP */
  126. #define    LONGDATA    2    /* Long data block -- full size spec'd by K */
  127. #define    SHORTDATA    3    /* Short data block -- first byte or two is
  128.                    count.  Full K-size packet is sent, even
  129.                    though the useful data is shorter. */
  130.  
  131. char *tt_pr[] = {"CONTROL", "ALTCHN", "LONGDATA", "SHORTDATA"};
  132.  
  133. /* If TT == CONTROL (also K will == KCONTROL) then
  134.    the x field is:             and the Y field means: */
  135. #define    CLOSE    1    /* End of communication */
  136. #define    RJ    2    /* Reject packet    last good packet # seen */
  137. #define    SRJ    3    /* Selective reject    seq # of bad packet, resend
  138.                SRJ is not used by UUCP. */
  139. #define    RR    4    /* Receiver Ready    last good packet # seen */
  140. #define    INITC    5    /* Init phase C        window size to hand sender */
  141. #define    INITB    6    /* Init phase B        max data segment size (K val)
  142.                         to hand sender */
  143. #define    INITA    7    /* Init phase A        window size to hand sender */
  144.  
  145. char *ctrl_pr[] = {"*ZERO*",
  146.     "CLOSE", "RJ", "SRJ", "RR", "INITC", "INITB", "INITA"};
  147.  
  148. /*
  149.  * If TT == LONGDATA or SHORTDATA then x field is the sequence # of this packet
  150.  * and y field is the last good packet # seen.
  151.  *
  152.  * In both data and RJ/RR packets, the "last good packet # seen" starts off
  153.  * as zero.
  154.  */
  155.  
  156.  
  157. #define    MAX_PACKET    4096
  158.  
  159. unsigned char    msgi[MAX_PACKET+SLOP],    /* Incoming packet */
  160.         msgo[MAX_PACKET+SLOP];    /* Outgoing packet */
  161.  
  162. int    firstslave,            /* First packet of slave's session */
  163.     msgsize,            /* Size of data part of msg */
  164.     tt, xxx, yyy,            /* Fields from control byte */
  165.     rseq,                /* Last good packet # we received */
  166.     his_rseq,            /* Last good packet # HE received */
  167.     wseq;                /* Next packet # we will send */
  168.  
  169. int    last_op;            /* Last data op: OP_READ or OP_WRITE */
  170. #define    OP_READ        0
  171. #define    OP_WRITE    1
  172.  
  173. int    reject;                /* Packet # to reject or NOREJECT */
  174. #define    NOREJECT    -1
  175.  
  176. /* Segments are encoded as (log2 length) - 3, except in INITB packet */
  177. #ifdef BUFFEREDIO
  178. int wndsiz = 7;            /* Ask them to send up to 7 packets */
  179. #else
  180. int wndsiz = 1;            /* Ask for window of 1 messages flying */
  181. #endif
  182. int segsiz = 2;            /* Ask for 64 byte messages */
  183. int sendseg = 2;        /* Size segments other guy wants to see */
  184. int sendwin = 1;        /* Size window other guy wants to see */
  185.  
  186. int sendbytes;            /* sendseg, in bytes */
  187.  
  188. int    segbytes[10] = {    /* K value (encoded segment size) */
  189.         -1,        /* 0 */
  190.         32,        /* 1 */
  191.         64,        /* 2 */
  192.         128,        /* 3 */
  193.         256,        /* 4 */
  194.         512,        /* 5 */
  195.         1024,        /* 6 */
  196.         2048,        /* 7 */
  197.         4096,        /* 8 */
  198.         0,        /* 9 = KCONTROL */
  199. };
  200.  
  201. /*
  202.  * Low level output routines.  These send packets without checking
  203.  * whether they got properly received.
  204.  *
  205.  * writeframe():
  206.  *
  207.  * Finish off an outgoing frame in msgo and queue it up to be written
  208.  * to the serial port.
  209.  *
  210.  * This routine is called to send each and every packet.
  211.  */
  212. int
  213. writeframe(cksm)
  214.     int cksm;
  215. {
  216.     
  217.     msgo[0] = DLE;
  218.     msgo[2] = cksm;
  219.     msgo[3] = cksm >> 8;
  220.     msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];
  221.  
  222.     if (DEBUG_LEVEL(9)) {
  223.         int i, maxlen;
  224.  
  225.         printf("T ");
  226.         maxlen = segbytes[msgo[LENBYTE]] + 6;
  227.         for (i = 0; i < maxlen; i++)
  228.             printf("%02x  ",msgo[i] & 0xFF);
  229.         putchar('\n');
  230.     }
  231.     if (DEBUG_LEVEL(6)) {
  232.         int t, x, y;
  233.  
  234.         t = msgo[CBYTE] >> 6;
  235.         x = (msgo[CBYTE] >> 3) & 7;
  236.         y = msgo[CBYTE] & 7;
  237.         if ((long)t == (long)CONTROL)
  238.             printf("Sent: CONTROL %s %d\n",
  239.                 ctrl_pr[x], y);
  240.         else
  241.             printf("Sent: %s %d %d\n",
  242.                 tt_pr[t], x, y);
  243.     }
  244.  
  245.     /*
  246.      * In our window=1 implementation, we just queue the packet
  247.      * up for transmission here (by leaving it in msgo[]).  It
  248.      * will be written next time we go through inpkt().
  249.      */
  250.     last_op = OP_WRITE;    /* Remember to avoid overwriting the packet */
  251.     return 0;        /* Never aborts */
  252. }
  253.  
  254. /* Send an ack */
  255. int
  256. ackmsg()
  257. {
  258.  
  259.     msgo[1] = KCONTROL;
  260.     if ((long)reject != (long)NOREJECT)
  261.         msgo[4] = (CONTROL << 6) | (RJ << 3) | reject;
  262.     else
  263.         msgo[4] = (CONTROL << 6) | (RR << 3) | rseq;
  264.     reject = NOREJECT;
  265.     return writeframe((int)(MAGIC - msgo[4]));
  266. }
  267.  
  268.  
  269. /* Send a control message other than an ack */
  270. int
  271. ctlmsg(byte)
  272. char byte;
  273. {
  274.  
  275.     msgo[1] = KCONTROL;
  276.     msgo[4] = (CONTROL << 6) | byte;
  277.     return writeframe((int)(MAGIC - msgo[4]));
  278. }
  279.  
  280. /*
  281.  * Medium level output routine.  This sends a short or long data packet
  282.  * and figures out when to retransmit and/or insert acknowledgements as
  283.  * needed.
  284.  */
  285. sendpacket(s, n, sorl)
  286.     char *s;
  287.     int n;
  288.     int sorl;            /* SHORTDATA or LONGDATA */
  289. {
  290.     int cksm, offset, difflen;
  291.  
  292.     if ((long)last_op == (long)OP_WRITE) {
  293.         /* Better get the first one sent and ack'd first */
  294.         /* FIXME, this will change for window > 1 */
  295.         if (inpkt()) return 1;
  296.     }
  297.  
  298.     bzero((char *)(msgo+6), sendbytes);
  299.     msgo[1] = sendseg;
  300.     msgo[4] = (sorl << 6) + (wseq << 3) + rseq;
  301.  
  302.     switch(sorl) {
  303.     case LONGDATA:
  304.         if (n > sendbytes) 
  305.             {
  306.                 logit("PROTOCOL VIOLATION IN SENDPACKET", "n > sendbytes");
  307.                 exit(1);
  308.                 }
  309.         offset = 6;
  310.         break;
  311.  
  312.     case SHORTDATA:
  313.         difflen = sendbytes - n;
  314.         if (difflen < 1) 
  315.         {
  316.                 logit("PROTOCOL VIOLATION IN SENDPACKET", "difflen < 1");
  317.                 exit(1);
  318.                 }
  319.         offset = 7;
  320.         if (difflen <= 127) {
  321.             msgo[6] = difflen;      /* One byte count */
  322.         } else {
  323.             msgo[6] = 128 | difflen;  /* low byte, with 0x80 on */
  324.             msgo[7] = difflen >> 7;   /* High byte */
  325.             offset = 8;
  326.         }
  327.     }
  328.  
  329.     bcopy(s, (char *)msgo+offset, n);        /* Move the data */
  330.  
  331.     cksm = MAGIC - (chksum(&msgo[6], sendbytes) ^ (0377 & msgo[4]));
  332.     wseq = (wseq + 1) & 7;            /* Bump sent pkt sequence # */
  333.     return writeframe(cksm);
  334. }
  335.  
  336. /*
  337.  * Medium level input routine.
  338.  *
  339.  * Write a packet to the serial port, then read a packet from the serial port.
  340.  * Return 1 if other side went away, 0 if good packet received.
  341.  *
  342.  * With window size of 1, we send a packet and then receive one.
  343.  * FIXME, when we implement a larger window size, this routine will become
  344.  * more complicated and callers will not be able to depend on msgo[]
  345.  * being sent and acknowledged when it returns.
  346.  */
  347. int
  348. inpkt()
  349. {
  350.     int data,count,need;
  351.     register int i;
  352.     unsigned short pktsum, oursum;
  353.     int status;
  354.     /*
  355.      * Next vars are for re-queueing received chars to rescan them
  356.      * for a valid packet after an error.
  357.      */
  358.     int queued = -1;  /* <0: off, 0: just finished, >0: # chars pending */
  359.     unsigned char *qp;
  360.     unsigned char qbuf[sizeof msgi];    /* This can be static if 4K
  361.                            on the stack is too much */
  362. #    define    bad(str) {if (DEBUG_LEVEL(5)) printf str; goto oops; }
  363.  
  364.     if (firstslave) {
  365.         firstslave = 0;
  366.         goto again;
  367.     }
  368.  
  369. xmit:
  370.     i = segbytes[msgo[LENBYTE]] + 6;
  371.     status = xwrite(0, (char *)msgo,i);
  372.     if ((long)status != (long)i) {
  373.         if (DEBUG_LEVEL(0)) {
  374.             printf("xmit %d bytes failed, status %d, errno %d", 
  375.                 i, status, errno);
  376.         }
  377.         return 1;        /* Write failed */
  378.     }
  379.  
  380. again:
  381.     count = 0;
  382.  
  383.     DEBUG(9, "R ", 0);
  384.  
  385.     while (1) {
  386.         if (queued >= 0) {
  387.             /*
  388.              * Process some stuff from a string.
  389.              * If we just finished the last char queued, and
  390.              * we are still scanning for a DLE, re-xmit our
  391.              * last packet before we continue reading.
  392.              * On the other hand, if we have a valid packet
  393.              * header accumulating, just keep reading the serial
  394.              * port.
  395.              */
  396.             if (--queued < 0) {
  397.                 if (count == 0) {
  398.                     DEBUG(6, "End queue.  Re-xmit.\n", 0);
  399.                     goto xmit; /* No packet comin' in */
  400.                 } else {
  401.                     DEBUG(6,"End queue.  Keep reading\n",0);
  402.                     goto readser; /* Seems to be sumpin' */
  403.                 }
  404.             }
  405.             data = *qp++;        /* Just grab from queue */
  406.         } else {
  407. readser:
  408.             data = xgetc();
  409.             if (data == EOF) break;
  410.         }
  411.  
  412.         if (DEBUG_LEVEL(9))
  413.             printf("%02x%c ",data & 0xFF, isprint(data)? data: ' ');
  414.  
  415.         switch (count)
  416.         {
  417.         case 0:
  418.             /* Look for DLE */
  419.             if (data == DLE)
  420.                 msgi[count++] = DLE;
  421.             break;
  422.  
  423.         case LENBYTE:
  424.             /* Check length byte */
  425.             if (data > KCONTROL || data == 0)
  426.                 bad(("packet size"));
  427.             if (segbytes[data] > MAX_PACKET) {
  428.                 bad(("packet too long for buffer"));
  429.         oops:
  430.                 if (DEBUG_LEVEL(5))
  431.                     printf(" bad in above packet\n");
  432.  
  433.                 /* FIXME, decode packet header here,
  434.                    if enough of it has come in. */
  435.  
  436.                 /* See if any DLEs in the bad packet */
  437.                 /* Skip 0, we know that's a DLE */
  438.                 for (i = 1; i < count; i++) {
  439.                     if (msgi[i] == DLE) {
  440.                         /* Reprocess from the DLE.
  441.                          * if queued, back up the q.
  442.                          * if not, make one.
  443.                          */
  444.                         if (queued >= 0) {
  445.                             queued += count - i;
  446.                             qp -= count - i;
  447.                     DEBUG(6,"Backup and rescan queue\n", 0);
  448.                         } else {
  449.                             bcopy((char *)msgi+i, (char *)qbuf, 
  450.                                 count - i);
  451.                             qp = qbuf;
  452.                             queued = count - i;
  453.                     DEBUG(6,"Queue and rescan input\n", 0);
  454.                         }
  455.                         goto again;
  456.                     }
  457.                 }
  458.  
  459.                 if (queued >= 0) {
  460.                     DEBUG(6, "Continue scan\n", 0);
  461.                     goto again;
  462.                 } else {
  463.                     DEBUG(6, "Re-xmit previous packet\n",0);
  464.                     goto xmit;    /* Xmit then rcv */
  465.                 }
  466.             }
  467.             msgi[count++] = (unsigned char)data;        /* Save it */
  468.             msgsize = segbytes[data];    /* Save Packet size */
  469.             need = 6 + msgsize;
  470.             break;
  471.  
  472.         case CBYTE:
  473.             /* Break up control byte as well as storing it */
  474.             msgi[count++] = (unsigned char)data;        /* Save it */
  475.             tt = (data >> 6) & 3;
  476.             xxx = (data >> 3) & 7;
  477.             yyy = data & 7;
  478.  
  479.             /* Now check it a bit */
  480.             switch (tt) {        /* Switch on msg type */
  481.             case CONTROL:
  482.                 /* Control msg must have KCONTROL size */
  483.                 if ((long)msgsize != (long)0) bad(("K versus Control"));
  484.                 /* We don't implement SRJ, nor does Unix */
  485.                 switch (xxx) {
  486.                 case SRJ:
  487.                     bad(("SRJ received"));
  488.                 case RJ:
  489.                 case RR:
  490.                     if ((long)yyy != (long)(7 & (wseq - 1)))
  491.                         bad(("didn't ack our pkt"));
  492.                 }
  493.                 break;
  494.             
  495.             case ALTCHN:
  496.                 bad(("ALTCHN received")); /* Unsupported */
  497.  
  498.             case SHORTDATA:
  499.             case LONGDATA:
  500.                 if (msgsize == 0) bad (("KCONTROL with data"));
  501.                 if (((xxx - rseq) & 7) > wndsiz) {
  502.                     /* Atari ST cpp has problems with
  503.                      * macro args broken across lines?
  504.                      * That's why funny indent here
  505.                      */
  506. bad (("data out of window, xxx=%d rseq=%d", xxx, rseq));
  507.                 }
  508.                 /* FIXME, below enforces window size == 1 */
  509.                 /* Note that this is also how we guarantee
  510.                    that msgo has been received OK by the time
  511.                    we exit inpkt() too.  Don't change it unless
  512.                    you know what you are doing. */
  513.                 if ((long)yyy != (long)(7 & (wseq - 1)))
  514.                     bad(("didn't ack our pkt"));
  515.                 break;
  516.             }
  517.             break;
  518.  
  519.         case FRAMEBYTE:
  520.             /* See whole frame, check it a bit. */
  521.             msgi[count++] = (unsigned char)data;
  522.             if ((long)data != (long)(msgi[1] ^ msgi[2] ^ msgi[3] ^ msgi[4]))
  523.                 bad(("frame checksum"));
  524.             pktsum = msgi[2] + (msgi[3] << 8);
  525.  
  526.             if (tt == CONTROL) {
  527.                 /* Check checksums for control packets */
  528.                 oursum = MAGIC - msgi[4];
  529.                 if ((long)pktsum != (long)oursum)
  530.                     bad(("control checksum"));
  531.                 /*
  532.                  * We have a full control packet.
  533.                  * Update received seq number for the ones
  534.                  * that carry one.
  535.                  */
  536.                 switch (xxx) {
  537.                 case RJ: case RR:
  538.                     if (((wseq - yyy) & 7) > sendwin) {
  539. bad (("RJ/RR out of window, yyy=%d wseq=%d", yyy, wseq));
  540.                     }
  541.                     his_rseq = yyy;
  542.                 }
  543.                 goto done;
  544.             } else {
  545.                 /*
  546.                  * Received frame of data packet.
  547.                  *
  548.                  * Now that the checksum has been verified,
  549.                  * we can believe the acknowledgement (if
  550.                  * any) in it.
  551.                  */
  552.                 if (((wseq - yyy) & 7) > sendwin) {
  553. bad (("data ack out of window, yyy=%d wseq=%d", yyy, wseq));
  554.                 }
  555.                 his_rseq = yyy;
  556.             }
  557.             break;
  558.  
  559.         default:
  560.             msgi[count++] = (unsigned char)data;
  561.             if (count >= need) {
  562.                 /* We have received a full data packet */
  563.                 oursum = MAGIC - (chksum(&msgi[6], sendbytes)
  564.                           ^ (0377 & msgi[4]));
  565.                 if ((long)pktsum != (long)oursum) {
  566.                     /* Send a reject on this pkt */
  567.                     reject = xxx - 1;
  568. bad(("\ndata checksum in packet %x, ours=%x", pktsum, oursum));
  569.                 }
  570.                 /* FIXME, this may change for window>1 */
  571.                 if ((long)xxx != (long)(rseq+1)%8 ) {
  572. bad(("Not next packet xxx=%d rseq=%d", xxx, rseq));
  573.                 }
  574.                 rseq = xxx;    /* We saw this pkt OK */
  575.         done:
  576.                 if (DEBUG_LEVEL(9))
  577.                     putchar('\n');
  578.                 if (DEBUG_LEVEL(6)) {
  579.                     if (tt == CONTROL)
  580.                         printf("Rcvd: CONTROL %s %d\n",
  581.                             ctrl_pr[xxx], yyy);
  582.                     else
  583.                         printf("Rcvd: %s %d %d\n",
  584.                             tt_pr[tt], xxx, yyy);
  585.                 }
  586.                 last_op = OP_READ;
  587.                 return(0);
  588.             }
  589.             break;
  590.         }
  591.     }
  592.     DEBUG(6, " EOF\n", 0);
  593.     return(1);
  594. }
  595.  
  596. int
  597. chksum(s,n)
  598. register unsigned char *s;
  599. register n;
  600. {
  601.     register short sum;
  602.     register unsigned short t;
  603.     register short x;
  604.  
  605.     sum = -1;
  606.     x = 0;
  607.     do {
  608.         if (sum < 0)
  609.         {
  610.             sum <<= 1;
  611.             sum++;
  612.         }
  613.         else
  614.             sum <<= 1;
  615.         t = sum;
  616.         sum += *s++ & 0377;
  617.         x += sum ^ n;
  618.         if ((unsigned short)sum <= t)
  619.             sum ^= x;
  620.     } while (--n > 0);
  621.  
  622.     return(sum);
  623. }
  624.  
  625. /*
  626.  * Medium level packet driver input routine.
  627.  *
  628.  * Read a data packet from the other side.  If called twice in succession,
  629.  * we send an ack of the previous packet.  Otherwise we tend to piggyback
  630.  * the acks on data packets.
  631.  *
  632.  * Result is 0 if we got a data packet, 1 if we got some other kind, or
  633.  * a hangup timeout.
  634.  */
  635. int
  636. indata()
  637. {
  638.  
  639.     while (1) {
  640.         if (last_op == OP_READ) {
  641.             ackmsg();        /* Send an ack */
  642.         }
  643.         if (inpkt()) return 1;
  644.  
  645.         switch (tt) {
  646.         case ALTCHN:
  647.             return 1;        /* Unsupported - yet */
  648.  
  649.         case LONGDATA:
  650.         case SHORTDATA:
  651.             /*
  652.              * We got a data packet.  That's what we want,
  653.              * so return.
  654.              */
  655.             return 0;        /* We are done. */
  656.  
  657.         case CONTROL:    
  658.             switch (xxx) {
  659.             default:
  660.                 return 1;    /* Bad packet type */
  661.  
  662.             case RJ:        /* Reject prev pkt */
  663.             case RR:        /* OK but no data */
  664.                 break;        /* Ack and try again */
  665.             }
  666.         }
  667.     }
  668. }
  669.  
  670. /*
  671.  * Open a conversation in the g protocol.  Medium level routine.
  672.  *
  673.  * We need to both send and receive each packet type in turn.
  674.  * If this sequence falters, we start over at INITA, trying a few more times.
  675.  *
  676.  * Returns 0 for success, 1 for failure.
  677.  */
  678. int
  679. gturnon(mastermode)
  680.     int mastermode;
  681. {
  682.     int tries = 0;
  683.     int step = 0;
  684.     static int which[] = {INITA, INITA, INITB, INITB, INITC, INITC};
  685.  
  686.     /* initialize protocol globals, e.g. packet sequence numbers */
  687.  
  688.     rseq = 0;        /* Last good packet # we have seen from him */
  689.     wseq = 1;        /* Next packet # we will send */
  690.     his_rseq = 0;        /* Last good Packet # he has seen from us */
  691.     reject = NOREJECT;    /* Don't reject first packet */
  692.     firstslave = mastermode? 0: 1;    /* About to do first slave packet? */
  693.  
  694.     if (mastermode) goto master_start;
  695.  
  696.     while (++tries <= 8) {
  697.         /* Receive an initialization packet and handle it */
  698.         if (inpkt() == 0 && tt == CONTROL && xxx == which[step]) {
  699.             switch (xxx) {
  700.             /* Remember we've seen it, grab value */
  701.             case INITA:
  702.             do_inita:
  703.                 sendwin = yyy;
  704.                 break;
  705.             case INITB:
  706.                 /*
  707.                  * Get preferred packet size for other guy,
  708.                  * but don't overrun our buffer space.
  709.                  * The encoded segment size is off-by-1 from
  710.                  * the one used in the K field in each packet.
  711.                  */
  712.                 do {
  713.                     sendseg = yyy+1;
  714.                     sendbytes = segbytes[sendseg];
  715.                 } while (sendbytes > MAX_PACKET && --yyy);
  716.                 break;
  717.             case INITC:
  718.                 sendwin = yyy;
  719.                 break;
  720.             }
  721.             if (++step >= 6)        /* Move forward */
  722.                 return 0;        /* We are done */
  723.         } else {
  724.             /* Start over, sigh */
  725.             step = 0;
  726.             if (xxx == INITA)    /* Start with his inita */
  727.                 goto do_inita;
  728.         }
  729.  
  730. master_start:
  731.         /*
  732.          * Transmit an initialization packet.
  733.          */
  734.         switch (which[step]) {
  735.         case INITA:
  736.             ctlmsg((INITA << 3) | wndsiz);
  737.             break;
  738.         case INITB:
  739.             ctlmsg((INITB << 3) | (segsiz - 1));
  740.             break;
  741.         case INITC:
  742.             ctlmsg((INITC << 3) | wndsiz);
  743.             break;
  744.         }
  745.         if (++step >= 6)
  746.             return 0;        /* We are done */
  747.     }
  748.     return 1;                /* Failure */
  749. }
  750.  
  751. /*
  752.  * Turn off conversation in the G protocol.  Medium level routine.
  753.  */
  754. int
  755. gturnoff()
  756. {
  757.  
  758.     /* In windowed protocol, we have to check if prev one's been ack'd */
  759.     int i;
  760.     if (last_op == OP_WRITE) {
  761.         if (inpkt()) return 1;
  762.     }
  763.     /* do */
  764.     {
  765.             ctlmsg(CLOSE << 3);
  766.             i = segbytes[msgo[LENBYTE]] + 6;
  767.             xwrite(0, (char *)msgo,i);
  768.     }
  769.     /* while ((tt != CONTROL) && (xxx != CLOSE)); */
  770.     return 0;
  771. }
  772.  
  773. /*
  774.  * Read a message from the other side.
  775.  *
  776.  * Messages are always contained in LONGDATA packets.  If a message is
  777.  * longer than a single packet, only the last packet will contain a null
  778.  * character.  Keep catenating them until you see the null.
  779.  *
  780.  * Return SUCCESS or FAIL.  If the received message is longer than our
  781.  * buffer, we eat the whole message, but return FAIL once it ends.
  782.  */
  783. int
  784. grdmsg(str, fn)
  785.     char *str;    /* Buffer to put it in, sized MAXMSGLEN */
  786.     int fn;        /* File descriptor to read it from */
  787. {
  788.     unsigned msglen;
  789.     unsigned totlen = 0;
  790.     unsigned oldlen;
  791.  
  792.     str[0] = '\0';        /* No command yet */
  793.     do {
  794.         if ((long)(indata()) || (long)tt != (long)LONGDATA)
  795.             return FAIL;
  796.         msgi[6+msgsize] = '\0';    /* Null terminate packet */
  797.         msglen = strlen((char *)msgi+6);
  798.         oldlen = totlen;
  799.         totlen += msglen;
  800.         if (totlen < MAXMSGLEN) {
  801.             strcat(str+oldlen,(char *)&msgi[6]);  /* Tack on to command */
  802.         }
  803.     } while (msglen == msgsize);    /* Loop if no null in pkt */
  804.  
  805.     return (totlen < MAXMSGLEN)? SUCCESS: FAIL;
  806. }
  807.  
  808.  
  809. /*
  810.  * Write a message to the other side.
  811.  *
  812.  * We write the first (or only) packet from our local bufr[], the
  813.  * rest comes straight out of the caller's string.
  814.  */
  815. int
  816. gwrmsg(type, str, fn)
  817.     char type;
  818.     char *str;
  819.     int fn;
  820. {
  821.     char bufr[MAX_PACKET];
  822.     char *ptr;
  823.     int thislen, totlen;
  824.     
  825.     bufr[0] = type;
  826.     totlen = strlen(str) + 1;
  827.     if (totlen > MAXMSGLEN) 
  828.         {
  829.             logit("PROTOCOL VIOLATION IN GWRMSG", "totlen > MAXMSGLEN");
  830.             exit(1);
  831.             }
  832.     
  833.     strncpy(&bufr[1], str, sendbytes-1);
  834.     ptr = bufr;
  835.     
  836.     for (;;) {
  837.         thislen = totlen;
  838.         if (thislen > sendbytes) thislen = sendbytes;
  839.         if (sendpacket(ptr, thislen, LONGDATA))
  840.             return FAIL;
  841.         totlen -= sendbytes;
  842.         if (totlen < 0) break;
  843.         if (ptr == bufr)    ptr = str + (sendbytes - 1);
  844.         else            ptr += sendbytes;
  845.     }
  846.  
  847.     return SUCCESS;
  848. }
  849.  
  850. /*
  851.  * Write a file to the other side.
  852.  */
  853. int
  854. gwrdata(file, fn)
  855.     FILE *file;        /* File to be sent */
  856.     int fn;            /* fd of serial line */
  857. {
  858.     char dskbuf[MAX_PACKET];    /* Disk I/O buffer */
  859.     int count;
  860.  
  861.     do {
  862.         count = fread(dskbuf, sizeof (char), sendbytes, file);
  863.         if (count < 0) return FAIL;    /* FIXME, should send EOF */
  864.         if (sendpacket(dskbuf, count,
  865.             (count == sendbytes)? LONGDATA: SHORTDATA))
  866.                 return FAIL;
  867.     } while (count);
  868.  
  869.     return SUCCESS;
  870. }
  871.  
  872. /*
  873.  * Read a file from the other side.
  874.  */
  875. int
  876. grddata(fn, file)
  877.     int fn;            /* File desc of serial line */
  878.     FILE *file;        /* stdio file ptr of file to read into */
  879. {
  880.     int offset;
  881.     int status;
  882.     int error = 0;
  883.  
  884.     do {
  885.         /* Read a packet, handle the data in it */
  886.         if (indata())
  887.             return FAIL;
  888.  
  889.         switch (tt) {
  890.         case LONGDATA:
  891.             /* FIXME, check this write */
  892.             offset = 6;
  893.             goto writeit;
  894.         case SHORTDATA:
  895.             if (msgi[6] & 0x80) {
  896.                 msgsize -=
  897.                   (msgi[7] << 7) | (127&msgi[6]);
  898.                 offset = 8;
  899.             } else {
  900.                 msgsize -= msgi[6];
  901.                 offset = 7;
  902.             }
  903.  
  904.         writeit:
  905.             /* FIXME:
  906.              * Consider skipping further writing if error != 0 */
  907.             if ((long)msgsize != (long)0) {
  908.                 status = fwrite((char *)&msgi[offset], sizeof (char),
  909.                         msgsize, file);
  910.                 if ((long)status != (long)msgsize) error++;
  911.             }
  912.             break;
  913.         }
  914.     } while ((long)msgsize != (long)0);
  915.  
  916.     return error? FAIL: SUCCESS;
  917. }
  918.